# cmake_minimum_required(VERSION 3.18)

# project(ProtoExample
#     LANGUAGES CXX
# )

# # 设置c++的标准
# set(CMAKE_CXX_STANDARD 11)

# # 1. 查找ProtoBuff 库要求版本是 》= 3.0

# find_package(Protobuf 3.0 REQUIRED)

# # 2. 搜索 proto的描述文件
# file(GLOB PROTO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto)

# # 3. 创建 protoc的生成的生成的文件目录
# set(PB_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/pb)
# file(MAKE_DIRECTORY ${PB_OUT_DIR})

# # 4. 初始化生产源代码的集，用于生成我们的静态库，用main使用
# set(GEN_SRCS "") # *.pb.cc
# set(GEN_HEADS "") # *.pb.h

# # 5. 为每一个proto文件生成对应的 .cc and .h文件

# foreach(PROTO ${PROTO_FILES})
#     # 5.1 获取不带扩展名的文件名
#     get_filename_component(BASE_NAME ${PROTO} NAME_WE) #   person

#     # 5.2 添加生成的 c++文件到源代码集合
#     list(APPEND GEN_SRCS ${PB_OUT_DIR}/${BASE_NAME}.pb.cc)
#     list(APPEND GEN_HEADS ${PB_OUT_DIR}/${BASE_NAME}.pb.h)

#     # 5.3 为每一个 proto生成 c++文件
#     add_custom_command(
#         OUTPUT "${PB_OUT_DIR}/${BASE_NAME}.pb.cc ${PB_OUT_DIR}/${BASE_NAME}.pb.h"
#         COMMAND protoc
#         ARGS --cpp_out=${PB_OUT_DIR}
#         -I ${CMAKE_CURRENT_SOURCE_DIR}/proto
#         ${PROTO}
#         DEPENDS ${PROTO}
#         COMMENT "从 *.proto 生成对应的c++代码"
#         VERBATIM

#     )
# endforeach()


# # 6. 添加出发生成 pb 文件的目标
# add_custom_target(generate_protobuf DEPENDS ${GEN_SRCS} ${GEN_HEADS})


# #7. 把proto生成的文件编译为静态库
# add_library(MyProto STATIC ${GEN_SRCS})
# add_dependencies(MyProto generate_protobuf)
# target_include_directories(MyProto INTERFACE 
#     ${PB_OUT_DIR}
# )

# target_link_libraries(MyProto PUBLIC 
#     protobuf::libprotobuf
# )

# # 8. 添加可执行程序
# add_executable(main main.cc)
# # 9. 添加依赖
# target_link_libraries(main PRIVATE MyProto)


cmake_minimum_required(VERSION 3.18)

project(ProtoExample
    LANGUAGES CXX
)

# 设置c++的标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)  # 强制要求C++11，避免兼容问题

# 1. 查找ProtoBuff 库要求版本是 >= 3.0
find_package(Protobuf 3.0 REQUIRED)
message(STATUS "找到 Protobuf: ${Protobuf_VERSION}")  # 打印Protobuf版本，确认找到

# 2. 搜索 proto的描述文件（关键：确保匹配到proto文件）
file(GLOB PROTO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto)
# 打印匹配到的proto文件，验证是否找到（调试用）
message(STATUS "匹配到的 .proto 文件: ${PROTO_FILES}")
if(NOT PROTO_FILES)
    message(FATAL_ERROR "未找到任何 .proto 文件！请检查 proto 目录是否存在 .proto 文件（如 person.proto）")
endif()

# 3. 创建 protoc 生成文件的目录
set(PB_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/pb)
file(MAKE_DIRECTORY ${PB_OUT_DIR})

# 4. 存储所有生成文件的路径（用于关联依赖）
set(GENERATED_FILES "")  # 合并 .pb.cc 和 .pb.h，简化依赖管理

# 5. 为每个 proto 文件生成对应的 C++ 文件
foreach(PROTO ${PROTO_FILES})
    get_filename_component(BASE_NAME ${PROTO} NAME_WE)  # 获取文件名（如 person.proto → person）
    get_filename_component(PROTO_DIR ${PROTO} DIRECTORY)  # 获取proto文件所在目录（避免路径问题）
    message(STATUS "PROTO_DIR : ${PROTO_DIR}")
    # 生成的 C++ 文件路径
    set(PB_CC ${PB_OUT_DIR}/${BASE_NAME}.pb.cc)
    set(PB_H ${PB_OUT_DIR}/${BASE_NAME}.pb.h)

    # 将生成文件添加到列表（用于后续依赖）
    list(APPEND GENERATED_FILES ${PB_CC} ${PB_H})

    # 自定义命令：调用 protoc 生成 C++ 代码（关键：OUTPUT 明确指定生成文件）
    add_custom_command(
        OUTPUT ${PB_CC} ${PB_H}  # 输出文件（必须与后续源文件路径完全一致）
        COMMAND protoc # 用 find_package 找到的 protoc（更可靠，避免环境变量问题）
        ARGS 
            --cpp_out=${PB_OUT_DIR}  # 生成C++代码的输出目录
            -I ${PROTO_DIR}  # proto文件的搜索路径（用实际目录，更稳定）
            ${PROTO}  # 当前处理的proto文件
        DEPENDS ${PROTO}  # 依赖：proto文件修改后重新生成
        COMMENT "生成 ${BASE_NAME}.pb.cc 和 ${BASE_NAME}.pb.h"
        VERBATIM
    )
endforeach()

# 6. （可选）创建生成文件的目标（方便手动触发生成：make generate_protobuf）
add_custom_target(generate_protobuf DEPENDS ${GENERATED_FILES})

# 7. 编译生成的文件为静态库（关键修改：直接用 GENERATED_FILES 作为源文件）
# CMake 看到源文件是 add_custom_command 的 OUTPUT，会自动等待生成后再编译
add_library(MyProto STATIC ${GENERATED_FILES})

# 依赖生成目标（确保先生成 .pb 文件，再编译库）
add_dependencies(MyProto generate_protobuf)

# 让使用 MyProto 的目标（如 main）能找到生成的头文件
target_include_directories(MyProto INTERFACE 
    ${PB_OUT_DIR}
)

# 链接 Protobuf 库（用 find_package 提供的目标，自动处理头文件和库路径）
target_link_libraries(MyProto PUBLIC 
    protobuf::libprotobuf
)

# 8. 添加可执行程序
add_executable(main main.cc)

# 9. 链接静态库（main 依赖 MyProto，间接依赖 Protobuf）
target_link_libraries(main PRIVATE MyProto)